package fogcore

import "fmt"

const (
	H_PLAYED   = 0 //落子成功，已经落子
	C_PLAYABLE = 1 //可以在该区域落子
	Y_YJ_CODE  = 2 //超出棋盘范围
	J_JF_CODE  = 3 //有己方棋子
	D_DF_CODE  = 4 //有对方棋子
	D_DJ_CODE  = 5 //打劫禁入点
	J_JR_CODE  = 6 //没有气禁入点
	C_CF_LZ    = 7 //重复落子
)

var (
	Y_YJ = &errorGame{"非法输入，超出棋盘范围！"}
	J_JF = &errorGame{"非法输入，有己方棋子！"}
	D_DF = &errorGame{"非法输入，有对方棋子！"}
	D_DJ = &errorGame{"非法输入，打劫禁入点！"}
	J_JR = &errorGame{"非法输入，没有气禁入点！"}
	C_CF = &errorGame{"非法输入，重复落子！"}
)

//FogGoGame 一盘游戏对局的基本对象
type FogGoGame struct {
	Board        Board        //棋盘
	PieceColor   PointStatus  //当前落子的一方
	History      []ColorPoint //落子记录
	CountBK      int          //黑棋吃子数
	CountWK      int          //白旗吃子数
	lastPoint    Vec2         //打劫判断，上一次落子点
	previousTake Vec2         //打劫判断
	tempP        []PointStatus
}

type ColorPoint struct {
	Point Vec2        //棋子坐标
	Color PointStatus //棋子颜色
}

func NewFogGoGame(n int, piece PointStatus) *FogGoGame {
	fogGo := FogGoGame{
		Board: Board{
			points: make([]PointStatus, n*n),
			n:      n,
		},
		PieceColor: piece,
		tempP:      make([]PointStatus, n*n),
	}
	fogGo.Board.masks = make([][]Mask, 3)
	fogGo.Board.masks[C_BLACK] = make([]Mask, n*n)
	fogGo.Board.masks[C_WHITE] = make([]Mask, n*n)
	return &fogGo
}

func (fog *FogGoGame) Print() {
	fmt.Println("Board is ")
	fog.Board.Print(fog.PieceColor)
	fmt.Println("PieceColor is ", fog.PieceColor)
}

func (fog *FogGoGame) Pass() {
	fog.PieceColor = fog.PieceColor.getOtherColor()
}

//FogGoMask 棋盘在视野中的情况，被迷雾笼罩后的情况
func (fog *FogGoGame) FogGoMask(pieceColor PointStatus) *FogGoGame {
	fogMake := *fog
	fogMake.pointsMask(pieceColor)
	return &fogMake
}

//对棋盘进行mask
func (fog *FogGoGame) pointsMask(pieceColor PointStatus) {
	for i := 0; i < len(fog.Board.points); i++ {
		fog.Board.points[i] &= PointStatus(fog.Board.masks[pieceColor][i])
	}
}

//canPlaced 判断能否在v点上下棋
func (fog *FogGoGame) CanPlaced(v Vec2) (int, error) {
	if fog.Board.rangeCheck(v) { //越界
		return Y_YJ_CODE, Y_YJ
	}
	if fog.Board.HasStones(v) { // 有子
		if fog.isSelfPiece(v) { // 有己方棋子
			return J_JF_CODE, J_JF
		}
		return D_DF_CODE, D_DF // 有对方棋子
	}
	if fog.Board.hasLiberty(v) { //落子周围没有其他棋子
		return C_PLAYABLE, nil
	}
	if len(fog.getSelfAroundPiece(v)) > 0 { //上下左右有己方棋子
		if fog.hasLargeHasLiberty(v) { //己方棋子也没气了
			return C_PLAYABLE, nil
		}
	}
	if fog.canCaptureOpps(v) { //能反杀对方
		t, ok := fog.isKo(v)
		if ok && t == fog.lastPoint && v == fog.previousTake { //是打劫的情况
			return D_DJ_CODE, D_DJ
		}
		return C_PLAYABLE, nil
	}
	return J_JR_CODE, J_JR
}

//placed 在v点上下棋
func (fog *FogGoGame) Placed(v Vec2) (int, error) {
	if len(fog.History) != 0 && fog.History[len(fog.History)-1] == (ColorPoint{Point: v, Color: fog.PieceColor}) {
		return C_CF_LZ, C_CF
	}
	s, goResult := fog.CanPlaced(v) //判断能否在v点上下棋
	if goResult != nil {
		if goResult == D_DF { //有对方棋子
			fog.Board.SetMask(fog.PieceColor, v, BARE_MASK)
			fog.History = append(fog.History, ColorPoint{Point: v, Color: fog.PieceColor})
		}
		if goResult == J_JR || goResult == D_DJ { //禁入点
			fog.Board.SetMask(fog.PieceColor, v, BARE_MASK)
			fog.History = append(fog.History, ColorPoint{Point: v, Color: fog.PieceColor})
			for _, m := range moves {
				if !fog.Board.rangeCheck(v.Add(m)) {
					fog.Board.SetMask(fog.PieceColor, v.Add(m), BARE_MASK)
				}
			}
		}
		return s, goResult
	}

	fog.History = append(fog.History, ColorPoint{Point: v, Color: fog.PieceColor})

	ls := fog.getOppsPieces(v) //获取上下左右四个方向的对方棋子
	if len(ls) > 0 {
		ck := fog.tryKillOpps(v) //尝试杀对面
		if fog.PieceColor == C_BLACK {
			fog.CountBK += ck
		} else {
			fog.CountWK += ck
		}
	}

	//落子并驱散四周迷雾
	fog.Board.SetPoint(v, fog.PieceColor)
	fog.Board.SetMask(fog.PieceColor, v, BARE_MASK)
	for _, m := range moves {
		if !fog.Board.rangeCheck(v.Add(m)) {
			fog.Board.SetMask(fog.PieceColor, v.Add(m), BARE_MASK)
		}
	}

	fog.lastPoint = v
	fog.PieceColor = fog.PieceColor.getOtherColor()
	return H_PLAYED, nil
}

//isOppsPiece 是敌人
func (fog *FogGoGame) isOppsPiece(v Vec2) bool {
	return fog.Board.GetPoint(v) == fog.PieceColor.getOtherColor()
}

//isSelfPiece 是队友
func (fog *FogGoGame) isSelfPiece(v Vec2) bool {
	return fog.Board.GetPoint(v) == fog.PieceColor
}

//获取上下左右四个方向的己方棋子
func (fog *FogGoGame) getSelfAroundPiece(v Vec2) []Vec2 {
	var selfPieces []Vec2
	for _, next := range moves {
		v1 := next.Add(v)
		if !fog.Board.rangeCheck(v1) && fog.isSelfPiece(v1) {
			selfPieces = append(selfPieces, v1)
		}
	}
	return selfPieces
}

//获取上下左右四个方向的对方棋子
func (fog *FogGoGame) getOppsPieces(v Vec2) []Vec2 {
	var ls []Vec2
	for _, yd := range moves {
		v1 := yd.Add(v)
		if !fog.Board.rangeCheck(v1) && fog.isOppsPiece(v1) {
			ls = append(ls, v1)
		}
	}
	return ls
}

//判断和v点相连的己方棋子有气吗
func (fog *FogGoGame) hasLargeHasLiberty(v Vec2) bool {
	arrset(fog.tempP, 0)
	SetArrPoint(fog.tempP, fog.Board.n, v, 1)
	selQueue := fog.getSelfAroundPiece(v)
	for len(selQueue) != 0 {
		v1 := selQueue[0]
		selQueue = selQueue[1:]
		for _, yd := range moves {
			v2 := yd.Add(v1)
			if !fog.Board.rangeCheck(v2) && GetArrPoint(fog.tempP, fog.Board.n, v2) != 1 {
				if fog.Board.isEmpty(v2) {
					return true
				}
				if fog.isSelfPiece(v2) { //队友
					selQueue = append(selQueue, v2)
					SetArrPoint(fog.tempP, fog.Board.n, v2, 1)
				}
			}
		}
	}
	return false
}

//能杀对面
func (fog *FogGoGame) canCaptureOpps(v Vec2) bool {
	arrset(fog.tempP, 0)
	ops := fog.getOppsPieces(v)
	for _, op := range ops {
		if GetArrPoint(fog.tempP, fog.Board.n, op) == 1 {
			continue
		}
		qs := true
		SetArrPoint(fog.tempP, fog.Board.n, op, 1)
		var queue []Vec2
		queue = append(queue, op)
		for len(queue) != 0 {
			v1 := queue[0]
			queue = queue[1:]
			for _, yd := range moves {
				v2 := yd.Add(v1)
				if v2 == (v) {
					continue
				}
				if !fog.Board.rangeCheck(v2) && GetArrPoint(fog.tempP, fog.Board.n, v2) != 1 {
					if fog.Board.isEmpty(v2) {
						qs = false
						continue
					}
					if fog.isOppsPiece(v2) {
						queue = append(queue, v2)
						SetArrPoint(fog.tempP, fog.Board.n, v2, 1)
					}
				}
			}
		}
		if qs {
			return qs
		}
	}
	return false
}

//是否是打劫
func (fog *FogGoGame) isKo(v Vec2) (Vec2, bool) {
	opVecs := fog.getOppsPieces(v)
	t := DfVec2
	for _, opv := range opVecs {
		is_t := true
		for _, m := range moves {
			v2 := opv.Add(m)
			if !fog.Board.rangeCheck(v2) && !(v2 == v) {
				if fog.isOppsPiece(v2) || (fog.Board.isEmpty(v2)) {
					is_t = false
					break
				}
			}
		}
		if is_t {
			if t == DfVec2 {
				t = opv
			} else {
				return DfVec2, false
			}
		}
	}
	if t != DfVec2 {
		return t, true
	}
	return DfVec2, false
}

//获取周围情况
func (fog *FogGoGame) getAroundColor(v Vec2) []ColorPoint {
	var ls []ColorPoint
	for _, m := range moves {
		v1 := m.Add(v)
		if !fog.Board.rangeCheck(v1) {
			p := ColorPoint{
				Point: v1,
				Color: fog.Board.GetPoint(v1),
			}
			ls = append(ls, p)
		}
	}
	return ls
}

//尝试杀对面
func (fog *FogGoGame) tryKillOpps(v Vec2) int {
	opVecs := fog.getOppsPieces(v)
	arrset(fog.tempP, 0)
	var sum int
	for _, opv := range opVecs {
		if GetArrPoint(fog.tempP, fog.Board.n, opv) == 1 {
			continue
		}
		qs := true
		SetArrPoint(fog.tempP, fog.Board.n, opv, 1)
		var queue []Vec2
		var ls []Vec2
		queue = append(queue, opv)
		ls = append(ls, opv)
		for len(queue) != 0 {
			v1 := queue[0]
			queue = queue[1:]
			for _, yd := range moves {
				v2 := yd.Add(v1)
				if v2 == v {
					continue
				}
				if !fog.Board.rangeCheck(v2) && GetArrPoint(fog.tempP, fog.Board.n, v2) != 1 {
					if fog.Board.isEmpty(v2) {
						qs = false
					}
					if fog.isOppsPiece(v2) {
						queue = append(queue, v2)
						ls = append(ls, v2)
						SetArrPoint(fog.tempP, fog.Board.n, v2, 1)
					}
				}
			}
		}
		if qs {
			for _, i := range ls {
				fog.Board.SetPoint(i, C_EMPTY)
			}
			if len(ls) == 1 {
				fog.previousTake = ls[0]
			}
			sum += len(ls)
		}
	}
	if sum != 1 {
		fog.previousTake = DfVec2
	}
	return sum
}

//胜利一方
func (fog *FogGoGame) winner() int {
	//TODO 不知道如何实现
	return 0
}

//形式判断
func (fog *FogGoGame) formJudgment() *Board {
	//TODO 不知道如何实现
	return nil
}

//初始化数组
func arrset(arr []PointStatus, value PointStatus) {
	for i := 0; i < len(arr); i++ {
		arr[i] = value
	}
}
